home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *RCSid = "$Id: parse.c,v 1.51 1995/12/02 22:04:35 drd Exp $";
- #endif
-
-
- /* GNUPLOT - parse.c */
- /*
- * Copyright (C) 1986 - 1993 Thomas Williams, Colin Kelley
- *
- * Permission to use, copy, and distribute this software and its documentation
- * for any purpose with or without fee is hereby granted, provided that the
- * above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation.
- *
- * Permission to modify the software is granted, but not the right to distribute
- * the modified code. Modifications are to be distributed as patches to
- * released version.
- *
- * This software is provided "as is" without express or implied warranty.
- *
- *
- * AUTHORS
- *
- * Original Software: Thomas Williams, Colin Kelley.
- *
- * Gnuplot 2.0 additions: Russell Lang, Dave Kotz, John Campbell.
- *
- * Gnuplot 3.0 additions: Gershon Elber and many others.
- *
- */
-
- #include <signal.h>
- #include <math.h>
- #include "plot.h"
- #include "help.h"
-
-
- RETSIGTYPE fpe __P((int an_int));
- static void extend_at __P((void));
- static union argument * add_action __P((enum operators sf_index));
- static void express __P((void));
- static void xterm __P((void));
- static void aterm __P((void));
- static void bterm __P((void));
- static void cterm __P((void));
- static void dterm __P((void));
- static void eterm __P((void));
- static void fterm __P((void));
- static void gterm __P((void));
- static void hterm __P((void));
- static void factor __P((void));
- static void xterms __P((void));
- static void aterms __P((void));
- static void bterms __P((void));
- static void cterms __P((void));
- static void dterms __P((void));
- static void eterms __P((void));
- static void fterms __P((void));
- static void gterms __P((void));
- static void hterms __P((void));
- static void iterms __P((void));
- static void unary __P((void));
-
- static struct at_type *at=NULL;
- static int at_size=0;
- #if defined(_Windows) && !defined(WIN32)
- static jmp_buf far fpe_env;
- #else
- static jmp_buf fpe_env;
- #endif
-
- #define dummy (struct value *) 0
-
- RETSIGTYPE fpe(an_int)
- int an_int;
- {
- #if defined(MSDOS) && !defined(__EMX__) && !defined(DJGPP) && !defined(_Windows) || defined(DOS386)
- /* thanks to lotto@wjh12.UUCP for telling us about this */
- _fpreset();
- #endif
-
- #ifdef OS2
- (void) signal(an_int, SIG_ACK);
- #else
- (void)signal(SIGFPE, (sigfunc)fpe);
- #endif
- undefined = TRUE;
- longjmp(fpe_env, TRUE);
- }
-
-
- #ifdef apollo
- #include <apollo/base.h>
- #include <apollo/pfm.h>
- #include <apollo/fault.h>
-
- /*
- * On an Apollo, the OS can signal a couple errors that are not mapped into
- * SIGFPE, namely signalling NaN and branch on an unordered comparison. I
- * suppose there are others, but none of these are documented, so I handle
- * them as they arise.
- *
- * Anyway, we need to catch these faults and signal SIGFPE.
- */
-
- pfm_$fh_func_val_t apollo_sigfpe(pfm_$fault_rec_t & fault_rec)
- {
- kill(getpid(), SIGFPE);
- return pfm_$continue_fault_handling;
- }
-
- apollo_pfm_catch()
- {
- status_$t status;
- pfm_$establish_fault_handler(fault_$fp_bsun, pfm_$fh_backstop,
- apollo_sigfpe, &status);
- pfm_$establish_fault_handler(fault_$fp_sig_nan, pfm_$fh_backstop,
- apollo_sigfpe, &status);
- }
- #endif
-
-
- void evaluate_at(at_ptr, val_ptr)
- struct at_type *at_ptr;
- struct value *val_ptr;
- {
- double temp, real();
-
- undefined = FALSE;
- errno = 0;
- reset_stack();
-
- #ifndef DOSX286
- if (setjmp(fpe_env))
- return; /* just bail out */
- (void)signal(SIGFPE, (sigfunc)fpe);
- #endif
-
- execute_at(at_ptr);
-
- #ifndef DOSX286
- (void)signal(SIGFPE, SIG_DFL);
- #endif
-
- if (errno == EDOM || errno == ERANGE) {
- undefined = TRUE;
- } else {
- (void)pop(val_ptr);
- check_stack();
- /* At least one machine (ATT 3b1) computes Inf without a SIGFPE */
- temp = real(val_ptr);
- if (temp > VERYLARGE || temp < -VERYLARGE) {
- undefined = TRUE;
- }
- }
- }
-
-
- struct value *
- const_express(valptr)
- struct value *valptr;
- {
- register int tkn = c_token;
- if (END_OF_COMMAND)
- int_error("constant expression required", c_token);
- dummy_func=NULL; /* div - no dummy variables in a constant expression */
- evaluate_at(temp_at(), valptr); /* run it and send answer back */
- if (undefined) {
- int_error("undefined value", tkn);
- }
- return (valptr);
- }
-
-
- /* if dummy_dunc=NULL on entry, do not attempt to compile dummy variables - div */
- struct at_type *
- temp_at()
- { /* build a static action table and return its
- * pointer */
-
- if(at!=NULL) {
- free(at);
- at=NULL;
- }
-
- at=(struct at_type *)alloc(sizeof(struct at_type), "action table");
-
- at->a_count = 0; /* reset action table !!! */
- at_size=MAX_AT_LEN;
- express();
- return (at);
- }
-
-
- /* build an action table, put it in dynamic memory, and return its pointer */
-
- struct at_type *
- perm_at()
- {
- register struct at_type *at_ptr;
- unsigned int len;
-
- (void)temp_at();
- len = sizeof(struct at_type) +
- (int)(at->a_count - MAX_AT_LEN) * (int)sizeof(struct at_entry);
- at_ptr = (struct at_type *) ralloc(at, (unsigned long)len, "perm_at");
- at=NULL; /* invalidate at pointer */
- return (at_ptr);
- }
-
- static void extend_at()
- {
- int newsize=sizeof(struct at_type) + at_size * sizeof(struct at_entry);
-
- at=ralloc(at, newsize, "extend_at");
- at_size+=MAX_AT_LEN;
- #ifdef DEBUG_STR
- fprintf(stderr, "Extending at size to %d\n", at_size);
- #endif
- }
-
- #ifdef NOCOPY
- /*
- * cheap and slow version of memcpy() in case you don't have one
- */
- memcpy(dest, src, len)
- char *dest, *src;
- unsigned int len;
- {
- while (len--)
- *dest++ = *src++;
- }
- #endif /* NOCOPY */
-
-
- /* moved from eval.c, the function is only called from this module */
- static union argument *
- add_action(sf_index)
- enum operators sf_index; /* index of p-code function */
- {
- if (at->a_count >= at_size) {
- extend_at();
- }
- at->actions[at->a_count].index = sf_index;
- return(&(at->actions[at->a_count++].arg));
- }
-
-
- static void express()
- { /* full expressions */
- xterm();
- xterms();
- }
-
- static void xterm()
- { /* ? : expressions */
- aterm();
- aterms();
- }
-
-
- static void aterm()
- {
- bterm();
- bterms();
- }
-
-
- static void bterm()
- {
- cterm();
- cterms();
- }
-
-
- static void cterm()
- {
- dterm();
- dterms();
- }
-
-
- static void dterm()
- {
- eterm();
- eterms();
- }
-
-
- static void eterm()
- {
- fterm();
- fterms();
- }
-
-
- static void fterm()
- {
- gterm();
- gterms();
- }
-
-
- static void gterm()
- {
- hterm();
- hterms();
- }
-
-
- static void hterm()
- {
- unary(); /* - things */
- iterms(); /* * / % */
- }
-
-
- static void factor()
- {
- register int value;
-
- if (equals(c_token, "(")) {
- c_token++;
- express();
- if (!equals(c_token, ")"))
- int_error("')' expected", c_token);
- c_token++;
- } else if (equals(c_token,"$")) {
- struct value a;
- if (!isanumber(++c_token))
- int_error("Column number expected", c_token);
- convert(&a, c_token++);
- if (a.type != INTGR || a.v.int_val < 0)
- int_error("Positive integer expected", c_token);
- add_action(DOLLARS)->v_arg = a;
- } else if (isanumber(c_token)) {
- convert(&(add_action(PUSHC)->v_arg), c_token);
- c_token++;
- } else if (isletter(c_token)) {
- if ((c_token + 1 < num_tokens) && equals(c_token + 1, "(")) {
- value = standard(c_token);
- if (value) { /* it's a standard function */
- c_token += 2;
- express();
- if (equals(c_token, ",")) {
- while (equals(c_token, ",")) {
- c_token += 1;
- express();
- }
- }
- if (!equals(c_token, ")"))
- int_error("')' expected", c_token);
- c_token++;
- (void)add_action(value);
- } else {
- int call_type = (int)CALL;
- value = c_token;
- c_token += 2;
- express();
- if (equals(c_token, ",")) {
- struct value num_params;
- num_params.type = INTGR;
- num_params.v.int_val = 1;
- while (equals(c_token, ",")) {
- num_params.v.int_val += 1;
- c_token += 1;
- express();
- }
- add_action(PUSHC)->v_arg = num_params;
- call_type = (int)CALLN;
- }
- if (!equals(c_token, ")"))
- int_error("')' expected", c_token);
- c_token++;
- add_action(call_type)->udf_arg = add_udf(value);
- }
- /* dummy_func==NULL is a flag to say no dummy variables active */
- } else if (dummy_func) {
- if (equals(c_token, c_dummy_var[0])) {
- c_token++;
- add_action(PUSHD1)->udf_arg = dummy_func;
- } else if (equals(c_token, c_dummy_var[1])) {
- c_token++;
- add_action(PUSHD2)->udf_arg = dummy_func;
- } else {
- int i, param = 0;
- for (i = 2; i < MAX_NUM_VAR; i++) {
- if (equals(c_token, c_dummy_var[i])) {
- struct value num_params;
- num_params.type = INTGR;
- num_params.v.int_val = i;
- param = 1;
- c_token++;
- add_action(PUSHC)->v_arg = num_params;
- add_action(PUSHD)->udf_arg = dummy_func;
- break;
- }
- }
- if (!param) { /* defined variable */
- add_action(PUSH)->udv_arg = add_udv(c_token);
- c_token++;
- }
- }
- /* its a variable, with no dummies active - div */
- } else {
- add_action(PUSH)->udv_arg = add_udv(c_token);
- c_token++;
- }
- }
- /* end if letter */
- else
- int_error("invalid expression ", c_token);
-
- /* add action code for ! (factorial) operator */
- while (equals(c_token, "!")) {
- c_token++;
- (void)add_action(FACTORIAL);
- }
- /* add action code for ** operator */
- if (equals(c_token, "**")) {
- c_token++;
- unary();
- (void)add_action(POWER);
- }
- }
-
-
-
- static void xterms()
- { /* create action code for ? : expressions */
-
- if (equals(c_token, "?")) {
- register int savepc1, savepc2;
- register union argument *argptr1, *argptr2;
- c_token++;
- savepc1 = at->a_count;
- argptr1 = add_action(JTERN);
- express();
- if (!equals(c_token, ":"))
- int_error("expecting ':'", c_token);
- c_token++;
- savepc2 = at->a_count;
- argptr2 = add_action(JUMP);
- argptr1->j_arg = at->a_count - savepc1;
- express();
- argptr2->j_arg = at->a_count - savepc2;
- }
- }
-
-
- static void aterms()
- { /* create action codes for || operator */
-
- while (equals(c_token, "||")) {
- register int savepc;
- register union argument *argptr;
- c_token++;
- savepc = at->a_count;
- argptr = add_action(JUMPNZ); /* short-circuit if already
- * TRUE */
- aterm();
- argptr->j_arg = at->a_count - savepc; /* offset for jump */
- (void)add_action(BOOLE);
- }
- }
-
-
- static void bterms()
- { /* create action code for && operator */
-
- while (equals(c_token, "&&")) {
- register int savepc;
- register union argument *argptr;
- c_token++;
- savepc = at->a_count;
- argptr = add_action(JUMPZ); /* short-circuit if already
- * FALSE */
- bterm();
- argptr->j_arg = at->a_count - savepc; /* offset for jump */
- (void)add_action(BOOLE);
- }
- }
-
-
- static void cterms()
- { /* create action code for | operator */
-
- while (equals(c_token, "|")) {
- c_token++;
- cterm();
- (void)add_action(BOR);
- }
- }
-
-
- static void dterms()
- { /* create action code for ^ operator */
-
- while (equals(c_token, "^")) {
- c_token++;
- dterm();
- (void)add_action(XOR);
- }
- }
-
-
- static void eterms()
- { /* create action code for & operator */
-
- while (equals(c_token, "&")) {
- c_token++;
- eterm();
- (void)add_action(BAND);
- }
- }
-
-
- static void fterms()
- { /* create action codes for == and !=
- * operators */
-
- while (TRUE) {
- if (equals(c_token, "==")) {
- c_token++;
- fterm();
- (void)add_action(EQ);
- } else if (equals(c_token, "!=")) {
- c_token++;
- fterm();
- (void)add_action(NE);
- } else
- break;
- }
- }
-
-
- static void gterms()
- { /* create action code for < > >= or <=
- * operators */
-
- while (TRUE) {
- /* I hate "else if" statements */
- if (equals(c_token, ">")) {
- c_token++;
- gterm();
- (void)add_action(GT);
- } else if (equals(c_token, "<")) {
- c_token++;
- gterm();
- (void)add_action(LT);
- } else if (equals(c_token, ">=")) {
- c_token++;
- gterm();
- (void)add_action(GE);
- } else if (equals(c_token, "<=")) {
- c_token++;
- gterm();
- (void)add_action(LE);
- } else
- break;
- }
-
- }
-
-
-
- static void hterms()
- { /* create action codes for + and - operators */
-
- while (TRUE) {
- if (equals(c_token, "+")) {
- c_token++;
- hterm();
- (void)add_action(PLUS);
- } else if (equals(c_token, "-")) {
- c_token++;
- hterm();
- (void)add_action(MINUS);
- } else
- break;
- }
- }
-
-
- static void iterms()
- { /* add action code for * / and % operators */
-
- while (TRUE) {
- if (equals(c_token, "*")) {
- c_token++;
- unary();
- (void)add_action(MULT);
- } else if (equals(c_token, "/")) {
- c_token++;
- unary();
- (void)add_action(DIV);
- } else if (equals(c_token, "%")) {
- c_token++;
- unary();
- (void)add_action(MOD);
- } else
- break;
- }
- }
-
-
- static void unary()
- { /* add code for unary operators */
- if (equals(c_token, "!")) {
- c_token++;
- unary();
- (void)add_action(LNOT);
- } else if (equals(c_token, "~")) {
- c_token++;
- unary();
- (void)add_action(BNOT);
- } else if (equals(c_token, "-")) {
- c_token++;
- unary();
- (void)add_action(UMINUS);
- } else if (equals(c_token, "+")) { /* unary + is no-op */
- c_token++;
- unary();
- } else
- factor();
- }
-